/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/***************************************************************************
 * Name: xtransport.h
 *
 * Purpose: transport layer base API define and implmentation
 *
 * Developer:
 *   wen.gu , 2023-07-25
 *
 * TODO:
 *
 ***************************************************************************/

#ifndef __XBUS_TRANSPORT_XTRANSPORT_H__
#define __XBUS_TRANSPORT_XTRANSPORT_H__

#include <string>
#include <memory>
#include <functional>
#include <map>

#include "xbus/core/xtype.h"
#include "xbus/core/xerror.h"
#include "xbus/core/xresult.h"
#include "xbus/transport/xdialer.h"
#include "xbus/transport/xlistener.h"

namespace xbus::transport {

class XTransportFactory {
public:
    using XDialerPtr = XDialer::XDialerPtr;
    using XListenerPtr = XListener::XListenerPtr;
public:
    virtual ~XTransportFactory() = default;
public:
    virtual XDialerPtr createDialer(const std::string& url, int32_t port = 0) = 0;
    virtual XListenerPtr createListener(const std::string& url, int32_t port = 0) = 0;
};


struct XTransportUrl {
    int32_t port = 0;
    std::string protocol;
    std::string url;
};

class XTransport final {
public:
    using XDialerPtr = XDialer::XDialerPtr;
    using XListenerPtr = XListener::XListenerPtr;
    using XErrC = core::XErrC;
    using XTransportFactoryPtr = std::shared_ptr<XTransportFactory>;
    using FactoryMap = std::map<std::string, XTransportFactoryPtr>;
protected:
    XTransport();
public:
    ~XTransport();

public:
    static XTransport& get();

public:
    XErrC registerFactory(const std::string& proto, XTransportFactoryPtr factory);
    XErrC unregisterFacotry(const std::string& proto);
    XTransportFactoryPtr findFactory(const std::string& proto);
public:
    /** url syntax:  "proto://xxx[:port]" 
     *  proto: the transport layer proctocol, e.g. tcp, udp, uds(unix domain socket)
     *  xxx:  the url address 
     *  [:port] :  option segment, only use for like tcp, udp and so on. 
     */
    core::XResult<XDialerPtr> createDialer(const std::string& url);
    core::XResult<XListenerPtr> createListener(const std::string& url);

public:
    XErrC parseUrl(const std::string& url, XTransportUrl& trans_url);
private:
    FactoryMap factories_;
};


} //namespace xbus::transport


#endif /** !__XBUS_TRANSPORT_XTRANSPORT_H__ */